/*
 * Copyright [2018] [Alex/libo(liboware@gmail.com)]
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.network.task.impl;


import com.hyts.network.config.DefaultNetwork;
import com.hyts.network.config.SystemProperties;
import com.hyts.network.error.ConnectionException;
import com.hyts.network.task.AbstractExecutor;
import com.hyts.network.task.AbstractTask;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.logging.Logger;

/**
 * @author LiBo/Alex
 * @see AbstractExecutor
 * @since v1.1
 * @version V1.0
 */
public abstract class HandlerTaskExecutor extends AbstractExecutor<Object, byte[], SelectionKey> {


    /**
     * field-name: logger
     * field-type: Logger
     * description: 日志输出器
     */
    private Logger logger = Logger.getLogger(this.getClass().getName());

    private int bufferSize;

    private String charset;
    
    private Selector selector;

    /**************************super class constructor************************************************/

    public HandlerTaskExecutor(SelectionKey clientModel) {
        super(clientModel);
        this.bufferSize = DefaultNetwork.DEFAULT_BUFFEER_SIZE;
        this.charset = SystemProperties.DEFAULT_HANDLER_CHARSET_ENCODING;
    }

    public HandlerTaskExecutor(AbstractTask<SelectionKey> task) {
        super(task);
        this.bufferSize = DefaultNetwork.DEFAULT_BUFFEER_SIZE;
        this.charset = SystemProperties.DEFAULT_HANDLER_CHARSET_ENCODING;
    }

    public HandlerTaskExecutor() {
        this.bufferSize = DefaultNetwork.DEFAULT_BUFFEER_SIZE;
        this.charset = SystemProperties.DEFAULT_HANDLER_CHARSET_ENCODING;
    }

    /**************************self class constructor************************************************/

    public HandlerTaskExecutor(int bufferSize,SelectionKey clientModel){
        super(clientModel);
        this.bufferSize = bufferSize;
        this.charset = SystemProperties.DEFAULT_HANDLER_CHARSET_ENCODING;
    }

    public HandlerTaskExecutor(String charset,SelectionKey clientModel){
        super(clientModel);
        this.bufferSize = DefaultNetwork.DEFAULT_BUFFEER_SIZE;
        this.charset = charset;
    }

    public HandlerTaskExecutor(int bufferSize,String charset,SelectionKey clientModel){
        super(clientModel);
        this.bufferSize = bufferSize;
        this.charset = charset;
    }


    @Override
    public byte[] result() {
        byte[] result = null;
        try {
            //结果集操作
            if (this.getClientModel().isAcceptable()) {
                logger.info("接收到客户端连接请求操作!");
                handlerConnection(this.getClientModel());
            } else if (this.getClientModel().isReadable()) {
                logger.info("开始读取客户端请求数据");
                result = handlerRead(this.getClientModel());
                logger.info("接收到客户端读请求操作数据："+ new String(result));
               /* try {
					((SocketChannel)this.getClientModel().channel()).register(this.selector, SelectionKey.OP_WRITE);
				} catch (ClosedChannelException e) {
					e.printStackTrace();
				}*/
                handlerWrite(this.getClientModel(), result);
                //return result;
            } else if (this.getClientModel().isWritable() && this.getClientModel().isValid()) {
                logger.info("向客户端写请求操作数据");
                handlerWrite(this.getClientModel(), result);
                try {
					((SocketChannel)this.getClientModel().channel()).register(this.selector, SelectionKey.OP_READ);
				} catch (ClosedChannelException e) {
					e.printStackTrace();
				}
            }
        }finally{
            try {
                this.getClientModel().channel().close();
            } catch (IOException e) {
                throw new ConnectionException("关闭通道失败！",e);
            }
        }
        return new byte[0];
    }

    /**
     * 执行操作运行
     * @return
     */
    public abstract byte[] deal(byte[] result);

    /**
     * author:Alex/Libo
     * create-date:2018/11/23
     * create-time:20:55
     * method-name: handlerConnection
     * param: SelectionKey
     * return:
     * description: 处理连接操作
     */
    private void handlerConnection(SelectionKey selectionKey){
        if(selectionKey != null){
            try {
                ((ServerSocketChannel)selectionKey.channel()).accept().configureBlocking(false).
                        register(selectionKey.selector(),SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
            } catch (IOException e) {
                throw new ConnectionException("处理器建立请求应答连接失败！",e);
            }
        }
    }

    /**
     * author:Alex/Libo
     * create-date:2018/11/23
     * create-time:20:55
     * method-name: handlerConnection
     * param: SelectionKey
     * return:
     * description: 处理读请求操作
     */
    private byte[] handlerRead(SelectionKey selectionKey){
        SocketChannel channel = ((SocketChannel)selectionKey.channel());
        ByteBuffer bytebuffer = (ByteBuffer) selectionKey.attachment();
        bytebuffer.clear();
        try {
            if(channel.read(bytebuffer) == -1){
                channel.close();
            }else{
                //bytebuffer.flip();
                return bytebuffer.array();
            }
        } catch (IOException e) {
            throw new ConnectionException("读取连接数据信息失败！",e);
        }
        return new byte[0];
    }

    /**
     * author:Alex/Libo
     * create-date:2018/11/23
     * create-time:20:55
     * method-name: handlerConnection
     * param: SelectionKey
     * return:
     * description: 处理写请求操作
     */
    private void handlerWrite(SelectionKey selectionKey,byte[] result){
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
        try{
            buffer.flip();
            logger.info("向客户端写请求操作数据");
            channel.write(ByteBuffer.wrap(deal(buffer.array())));
            buffer.flip();
            //buffer.clear();
        } catch (IOException e) {
            throw new ConnectionException("服务端写入数据失败！",e);
        }
    }

	public void setSelector(Selector selector) {
		this.selector = selector;
	}
    
}
